// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.


#include "runtime_types.h"
#include "type.h"

#include "assert.h"
#include "panic.h"
#include "mem_alloc.h"
#include "interface.h"
#include "util.h"
#include "string.h"

// This is called by the compiler to convert a value from one
// interface type to another.

void *
__go_convert_interface(const struct __go_type_descriptor *lhs_descriptor,
	const struct __go_type_descriptor *rhs_descriptor)
{
	return __go_convert_interface_2(lhs_descriptor, rhs_descriptor, 0);
}

// This is called when converting one interface type into another
// interface type.  LHS_DESCRIPTOR is the type descriptor of the
// resulting interface.  RHS_DESCRIPTOR is the type descriptor of the
// object being converted.  This builds and returns a new interface
// method table.  If any method in the LHS_DESCRIPTOR interface is not
// implemented by the object, the conversion fails.  If the conversion
// fails, then if MAY_FAIL is true this returns NULL; otherwise, it
// panics.

void *
__go_convert_interface_2(const struct __go_type_descriptor *lhs_descriptor,
	const struct __go_type_descriptor *rhs_descriptor, _Bool may_fail)
{
	const struct __go_interface_type *lhs_interface;
	int lhs_method_count;
	const struct __go_interface_method *lhs_methods;
	const void **methods;
	const struct __go_uncommon_type *rhs_uncommon;
	int rhs_method_count;
	const struct __go_method *p_rhs_method;
	int i;

	if (rhs_descriptor == NULL) {
		// A nil value always converts to nil.
		return NULL;
	}

	__go_assert(lhs_descriptor->__code == GO_INTERFACE);
	lhs_interface = (const struct __go_interface_type *)lhs_descriptor;
	lhs_method_count = lhs_interface->__methods.__count;
	lhs_methods = ((const struct __go_interface_method *)lhs_interface->__methods.__values);

	// This should not be called for an empty interface.
	__go_assert(lhs_method_count > 0);

	rhs_uncommon = rhs_descriptor->__uncommon;
	if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0) {
		struct __go_empty_interface panic_arg;

		if (may_fail)
			return NULL;

		runtime_newTypeAssertionError(
			NULL,
			rhs_descriptor->__reflection,
			lhs_descriptor->__reflection,
			lhs_methods[0].__name,
			&panic_arg);

		__go_panic(panic_arg);
	}

	rhs_method_count = rhs_uncommon->__methods.__count;
	p_rhs_method = ((const struct __go_method *)rhs_uncommon->__methods.__values);

	methods = NULL;

	for (i = 0; i < lhs_method_count; ++i) {
		const struct __go_interface_method *p_lhs_method;

		p_lhs_method = &lhs_methods[i];

		while (rhs_method_count > 0 &&
			(!__go_ptr_strings_equal(p_lhs_method->__name, p_rhs_method->__name) ||
				!__go_ptr_strings_equal(p_lhs_method->__pkg_path, p_rhs_method->__pkg_path)))
		{
			++p_rhs_method;
			--rhs_method_count;
		}

		if (rhs_method_count == 0 ||
			!__go_type_descriptors_equal(p_lhs_method->__type, p_rhs_method->__mtype))
		{
			struct __go_empty_interface panic_arg;

			if (methods != NULL)
				runtime_free(methods);

			if (may_fail)
				return NULL;

			runtime_newTypeAssertionError(
				NULL,
				rhs_descriptor->__reflection,
				lhs_descriptor->__reflection,
				p_lhs_method->__name,
				&panic_arg);

			__go_panic(panic_arg);
		}

		if (methods == NULL) {
			methods = (const void **)runtime_malloc((lhs_method_count + 1) * sizeof(void *));

			// The first field in the method table is always the type of the object.
			methods[0] = rhs_descriptor;
		}

		methods[i + 1] = p_rhs_method->__function;
	}

	return methods;
}

// Return whether we can convert from the type in FROM_DESCRIPTOR to
// the interface in TO_DESCRIPTOR.  This is used for type
// switches.

_Bool
__go_can_convert_to_interface(const struct __go_type_descriptor * to_descriptor,
	const struct __go_type_descriptor * from_descriptor)
{
	const struct __go_interface_type *to_interface;
	int to_method_count;
	const struct __go_interface_method *to_method;
	const struct __go_uncommon_type *from_uncommon;
	int from_method_count;
	const struct __go_method *from_method;
	int i;

	// In a type switch FROM_DESCRIPTOR can be NULL.
	if (from_descriptor == NULL)
		return 0;

	__go_assert(to_descriptor->__code == GO_INTERFACE);
	to_interface = (const struct __go_interface_type *)to_descriptor;
	to_method_count = to_interface->__methods.__count;
	to_method = ((const struct __go_interface_method *)to_interface->__methods.__values);

	from_uncommon = from_descriptor->__uncommon;
	if (from_uncommon == NULL) {
		from_method_count = 0;
		from_method = NULL;
	} else {
		from_method_count = from_uncommon->__methods.__count;
		from_method = ((const struct __go_method *)from_uncommon->__methods.__values);
	}

	for (i = 0; i < to_method_count; ++i) {
		while (from_method_count > 0 &&
			(!__go_ptr_strings_equal(from_method->__name, to_method->__name) ||
				!__go_ptr_strings_equal(from_method->__pkg_path, to_method->__pkg_path)))
		{
			++from_method;
			--from_method_count;
		}

		if (from_method_count == 0)
			return 0;

		if (!__go_type_descriptors_equal(from_method->__mtype, to_method->__type))
			return 0;

		++to_method;
		++from_method;
		--from_method_count;
	}

	return 1;
}

// Compare two interface values.
// Return 0 for equal, not zero for not equal (return value is like strcmp).

int
__go_empty_interface_compare(struct __go_empty_interface left, struct __go_empty_interface right)
{
	const struct __go_type_descriptor *left_descriptor;

	left_descriptor = left.__type_descriptor;

	if (((uintptr) left_descriptor & reflectFlags) != 0 ||
			((uintptr) right.__type_descriptor & reflectFlags) != 0)
		runtime_panicstring("invalid interface value");

	if (left_descriptor == NULL && right.__type_descriptor == NULL)
		return 0;
	if (left_descriptor == NULL || right.__type_descriptor == NULL)
		return 1;
	if (!__go_type_descriptors_equal(left_descriptor, right.__type_descriptor))
		return 1;
	if (__go_is_pointer_type(left_descriptor))
		return left.__object == right.__object ? 0 : 1;
	if (!left_descriptor->__equalfn(left.__object, right.__object, left_descriptor->__size))
		return 1;
	return 0;
}

// Compare an empty interface with a value.
// Return 0 for equal, not zero for not equal (return value is like strcmp).

int
__go_empty_interface_value_compare(struct __go_empty_interface left,
	const struct __go_type_descriptor *right_descriptor, const void *val)
{
	const struct __go_type_descriptor *left_descriptor;

	left_descriptor = left.__type_descriptor;
	if (((uintptr) left_descriptor & reflectFlags) != 0)
		runtime_panicstring("invalid interface value");
	if (left_descriptor == NULL)
		return 1;
	if (!__go_type_descriptors_equal(left_descriptor, right_descriptor))
		return 1;
	if (__go_is_pointer_type(left_descriptor))
		return left.__object == val ? 0 : 1;
	if (!left_descriptor->__equalfn(left.__object, val, left_descriptor->__size))
		return 1;
	return 0;
}

// Compare two interface values.
// Return 0 for equal, not zero for not equal (return value is like strcmp).

int
__go_interface_compare(struct __go_interface left, struct __go_interface right)
{
	const struct __go_type_descriptor *left_descriptor;

	if (left.__methods == NULL && right.__methods == NULL)
		return 0;
	if (left.__methods == NULL || right.__methods == NULL)
		return 1;
	left_descriptor = left.__methods[0];
	if (!__go_type_descriptors_equal(left_descriptor, right.__methods[0]))
		return 1;
	if (__go_is_pointer_type(left_descriptor))
		return left.__object == right.__object ? 0 : 1;
	if (!left_descriptor->__equalfn(left.__object, right.__object, left_descriptor->__size))
		return 1;
	return 0;
}

// Compare a non-empty interface value with an empty interface value.
// Return 0 for equal, not zero for not equal (return value is like
// strcmp).

int
__go_interface_empty_compare(struct __go_interface left, struct __go_empty_interface right)
{
	const struct __go_type_descriptor *left_descriptor;

	if (((uintptr) right.__type_descriptor & reflectFlags) != 0)
		runtime_panicstring("invalid interface value");
	if (left.__methods == NULL && right.__type_descriptor == NULL)
		return 0;
	if (left.__methods == NULL || right.__type_descriptor == NULL)
		return 1;
	left_descriptor = left.__methods[0];
	if (!__go_type_descriptors_equal(left_descriptor, right.__type_descriptor))
		return 1;
	if (__go_is_pointer_type(left_descriptor))
		return left.__object == right.__object ? 0 : 1;
	if (!left_descriptor->__equalfn(left.__object, right.__object, left_descriptor->__size))
		return 1;
	return 0;
}

// Compare two interface values.
// Return 0 for equal, not zero for not equal (return value is like strcmp).

int
__go_interface_value_compare(struct __go_interface left,
	const struct __go_type_descriptor *right_descriptor, const void *val)
{
	const struct __go_type_descriptor *left_descriptor;

	if (left.__methods == NULL)
		return 1;
	left_descriptor = left.__methods[0];
	if (!__go_type_descriptors_equal(left_descriptor, right_descriptor))
		return 1;
	if (__go_is_pointer_type(left_descriptor))
		return left.__object == val ? 0 : 1;
	if (!left_descriptor->__equalfn(left.__object, val, left_descriptor->__size))
		return 1;
	return 0;
}

// Check that an interface type matches for a conversion to a
// non-interface type.  This panics if the types are bad.  The actual
// extraction of the object is inlined.

void
__go_check_interface_type (const struct __go_type_descriptor *lhs_descriptor,
	const struct __go_type_descriptor *rhs_descriptor,
	const struct __go_type_descriptor *rhs_inter_descriptor)
{
	if (rhs_descriptor == NULL) {
		struct __go_empty_interface panic_arg;

		runtime_newTypeAssertionError(NULL, NULL, lhs_descriptor->__reflection,
			NULL, &panic_arg);

		__go_panic(panic_arg);
	}

	if (lhs_descriptor != rhs_descriptor &&
			!__go_type_descriptors_equal(lhs_descriptor, rhs_descriptor) &&
			(lhs_descriptor->__code != GO_UNSAFE_POINTER ||
				!__go_is_pointer_type (rhs_descriptor)) &&
			(rhs_descriptor->__code != GO_UNSAFE_POINTER ||
				!__go_is_pointer_type (lhs_descriptor)))
	{
		struct __go_empty_interface panic_arg;

		runtime_newTypeAssertionError(rhs_inter_descriptor->__reflection,
			rhs_descriptor->__reflection,
			lhs_descriptor->__reflection,
			NULL, &panic_arg);

		__go_panic(panic_arg);
	}
}

// This is called by the compiler to implement a type assertion from
// one interface type to another.  This returns the value that should
// go in the first field of the result tuple.  The result may be an
// empty or a non-empty interface.

const void *__go_assert_interface(const struct __go_type_descriptor *lhs_descriptor,
	const struct __go_type_descriptor *rhs_descriptor)
{
	const struct __go_interface_type *lhs_interface;

	if (rhs_descriptor == NULL) {
		struct __go_empty_interface panic_arg;

		// A type assertion is not permitted with a nil interface.

		runtime_newTypeAssertionError(NULL, NULL, lhs_descriptor->__reflection, NULL, &panic_arg);
		__go_panic(panic_arg);
	}

	// A type assertion to an empty interface just returns the object descriptor.

	__go_assert(lhs_descriptor->__code == GO_INTERFACE);
	lhs_interface = (const struct __go_interface_type *)lhs_descriptor;
	if (lhs_interface->__methods.__count == 0)
		return rhs_descriptor;

	return __go_convert_interface_2(lhs_descriptor, rhs_descriptor, 0);
}
